<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>08 简易拖拽实例 - take, first, takeUntil, concatAll · ShaofeiZi Blog · 做个日常记录</title>
    <meta name="description" content="訾绍飞的博客。万物皆有裂缝处，那是光射进来的地方。">
    <link rel="shortcut icon" href="/BLOG/favicon.ico">
  <link rel="manifest" href="/BLOG/manifest.json">
  <meta name="theme-color" content="#3F51B5">
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
  <link rel="apple-touch-icon" href="/BLOG/icons/192.png">
  <link rel="mask-icon" href="/BLOG/icons/safari-pinned-tab.svg" color="#3eaf7c">
  <meta name="msapplication-TileImage" content="/icons/192.png">
  <meta name="msapplication-TileColor" content="#3F51B5">
    
    <link rel="preload" href="/BLOG/assets/css/42.styles.90045bd1.css" as="style"><link rel="preload" href="/BLOG/assets/js/app.1a725be8.js" as="script"><link rel="preload" href="/BLOG/assets/js/26.407b2583.js" as="script"><link rel="prefetch" href="/BLOG/assets/js/7.88ba0bb7.js"><link rel="prefetch" href="/BLOG/assets/js/0.d3e592bd.js"><link rel="prefetch" href="/BLOG/assets/js/1.39b9c99c.js"><link rel="prefetch" href="/BLOG/assets/js/2.68dc10c9.js"><link rel="prefetch" href="/BLOG/assets/js/3.dfebdd5e.js"><link rel="prefetch" href="/BLOG/assets/js/4.ea97a821.js"><link rel="prefetch" href="/BLOG/assets/js/5.d8c2ecbf.js"><link rel="prefetch" href="/BLOG/assets/js/6.e51cd79c.js"><link rel="prefetch" href="/BLOG/assets/js/8.d9eebc06.js"><link rel="prefetch" href="/BLOG/assets/js/9.1a541d13.js"><link rel="prefetch" href="/BLOG/assets/js/10.4ec9ca67.js"><link rel="prefetch" href="/BLOG/assets/js/11.02558377.js"><link rel="prefetch" href="/BLOG/assets/js/12.d0e2086f.js"><link rel="prefetch" href="/BLOG/assets/js/13.5af02ddd.js"><link rel="prefetch" href="/BLOG/assets/js/14.5d9fcbf2.js"><link rel="prefetch" href="/BLOG/assets/js/15.ca0178b2.js"><link rel="prefetch" href="/BLOG/assets/js/16.cd99d056.js"><link rel="prefetch" href="/BLOG/assets/js/17.56f11c1d.js"><link rel="prefetch" href="/BLOG/assets/js/18.21837cc7.js"><link rel="prefetch" href="/BLOG/assets/js/19.73335fea.js"><link rel="prefetch" href="/BLOG/assets/js/20.1632ab79.js"><link rel="prefetch" href="/BLOG/assets/js/21.43175244.js"><link rel="prefetch" href="/BLOG/assets/js/22.5b7c0cca.js"><link rel="prefetch" href="/BLOG/assets/js/23.e624ba97.js"><link rel="prefetch" href="/BLOG/assets/js/24.ac5f7b41.js"><link rel="prefetch" href="/BLOG/assets/js/25.6934a11d.js"><link rel="prefetch" href="/BLOG/assets/js/27.7449d673.js"><link rel="prefetch" href="/BLOG/assets/js/28.52e25437.js"><link rel="prefetch" href="/BLOG/assets/js/29.fba21f3a.js"><link rel="prefetch" href="/BLOG/assets/js/30.2cd6d3e2.js"><link rel="prefetch" href="/BLOG/assets/js/31.0b0a749f.js"><link rel="prefetch" href="/BLOG/assets/js/32.92134487.js"><link rel="prefetch" href="/BLOG/assets/js/33.ad2b89cc.js"><link rel="prefetch" href="/BLOG/assets/js/34.9b22334e.js"><link rel="prefetch" href="/BLOG/assets/js/35.825f3d75.js"><link rel="prefetch" href="/BLOG/assets/js/36.cc3da84c.js"><link rel="prefetch" href="/BLOG/assets/js/37.8f339f62.js"><link rel="prefetch" href="/BLOG/assets/js/38.5674618f.js"><link rel="prefetch" href="/BLOG/assets/js/39.180f0d85.js"><link rel="prefetch" href="/BLOG/assets/js/40.275f26e3.js"><link rel="prefetch" href="/BLOG/assets/js/41.ce0f5927.js">
    <link rel="stylesheet" href="/BLOG/assets/css/42.styles.90045bd1.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div data-app="true" id="app" class="application theme--light"><div class="application--wrap"><div class="v-progress-linear blog-progress" style="height:3px;display:none;"><div class="v-progress-linear__background accent" style="height:3px;opacity:0.4;width:100%;"></div><div class="v-progress-linear__bar"><!----><div class="v-progress-linear__bar__determinate accent" style="width:0%;"></div></div></div><aside class="v-navigation-drawer v-navigation-drawer--close v-navigation-drawer--fixed v-navigation-drawer--is-mobile" style="height:100%;margin-top:0px;max-height:calc(100% - 0px);transform:translateX(-240px);width:240px;"><div><div class="aside-brand-wrap"><div class="aside-brand"><a href="/BLOG/" class="aside-avatar elevation-2 router-link-active"><img src="/BLOG/face.png" alt="avatar"></a><hgroup class="mt-3 variant-hide"><div class="subheading white--text">訾绍飞</div><a href="mailto:zishaofei221@gmail.com" title="zishaofei221@gmail.com" class="aside-mail primary--text text--lighten-5">zishaofei221@gmail.com</a></hgroup></div></div><hr class="v-divider theme--dark"><div class="v-list nav-list"><div class="secondary--text"><a href="/BLOG/" class="v-list__tile v-list__tile--link"><div class="v-list__tile__avatar"><div class="v-avatar" style="height:40px;width:40px;"><i class="fa fa-home"></i></div></div><div class="v-list__tile__content">首页</div></a></div><div class="secondary--text"><a href="/BLOG/tags" class="v-list__tile v-list__tile--link"><div class="v-list__tile__avatar"><div class="v-avatar" style="height:40px;width:40px;"><i class="fa fa-tag"></i></div></div><div class="v-list__tile__content">标签</div></a></div><div class="secondary--text"><a href="https://github.com/ShaofeiZi" target="_blank" class="v-list__tile v-list__tile--link"><div class="v-list__tile__avatar"><div class="v-avatar" style="height:40px;width:40px;"><i class="fab fa-github"></i></div></div><div class="v-list__tile__content">Github</div></a></div><div class="secondary--text"><a href="/BLOG/about" class="v-list__tile v-list__tile--link"><div class="v-list__tile__avatar"><div class="v-avatar" style="height:40px;width:40px;"><i class="fa fa-user-secret"></i></div></div><div class="v-list__tile__content">About</div></a></div></div></div><div class="v-navigation-drawer__border"></div></aside><nav class="blog-toolbar v-toolbar v-toolbar--fixed theme--dark primary" style="margin-top:0px;padding-right:0px;padding-left:0px;transform:translateY(0px);"><div class="v-toolbar__content" style="height:56px;"><button type="button" class="v-btn v-btn--icon"><div class="v-btn__content"><i class="fa fa-bars"></i></div></button><div class="v-toolbar__title">08 简易拖拽实例 - take, first, takeUntil, concatAll</div><div class="spacer"></div><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""><!----></div><div class="v-menu" style="display:none;"><div class="v-menu__activator"><button type="button" class="v-btn v-btn--icon"><div class="v-btn__content"><i class="fa fa-share-alt"></i></div></button></div><div class="v-menu__content" style="max-height:auto;min-width:0px;max-width:auto;top:12px;left:0px;transform-origin:top right;z-index:0;display:none;"><div class="v-list"><div class="secondary--text"><a class="v-list__tile v-list__tile--link"><div class="v-list__tile__avatar"><div class="v-avatar" style="height:40px;width:40px;"><i class="fa fa-lg fa-copy"></i></div></div><div class="v-list__tile__title">复制链接</div></a></div></div><input type="text" tabindex="-1" aria-hidden="true" value="" class="fake-hide"></div></div></div></nav><main class="v-content" style="padding-top:56px;padding-right:0px;padding-bottom:0px;padding-left:0px;"><div class="v-content__wrap"><div class="container blog-container grid-list-xl align-center"><div class="layout row wrap"><div class="flex mb-3 xs12"><article class="v-card elevation-16 post-card" style="height:undefined;"><div class="v-card__title"><div class="flex xs12"><h2 class="display-1 mb-3">08 简易拖拽实例 - take, first, takeUntil, concatAll</h2><div class="post-meta"><time datetime="2018-04-29T12:16:00.000Z" class="secondary--text post-time">2018年04月29日</time></div></div></div><div class="v-card__text pt-0 pb-0"><div class="flex xs12"><div class="content custom"><h1 id="_30-天精通-rxjs-08-：简易拖拽实例-take-first-takeuntil-concatall"><a href="#_30-天精通-rxjs-08-：简易拖拽实例-take-first-takeuntil-concatall" aria-hidden="true" class="header-anchor">#</a> 30 天精通 RxJS (08)：简易拖拽实例 - take, first, takeUntil, concatAll</h1><blockquote><p>如果是你会如何实现拖拽的功能？</p></blockquote><p>这是【30天精通 RxJS】的 08 篇，如果还没看过 07 篇可以往这边走：
<a href="https://github.com/ShaofeiZi/30-days-proficient-in-rxjs/blob/master/30%20%E5%A4%A9%E7%B2%BE%E9%80%9A%20RxJS%20(07)%EF%BC%9A%20Observable%20Operators%20%26%20Marble%20Diagrams.md" target="_blank" rel="noopener noreferrer">30 天精通 RxJS (07)： Observable Operators &amp; Marble Diagrams</a></p><p>今天建议大家直接看<a href="https://www.youtube.com/watch?v=bgi3Uaab1ok" target="_blank" rel="noopener noreferrer">影片</a></p><p>我们今天要接着讲 take, first, takeUntil, concatAll 这四个 operators，并且实例一个简易的拖拽功能。</p><h2 id="operators"><a href="#operators" aria-hidden="true" class="header-anchor">#</a> Operators</h2><h3 id="take"><a href="#take" aria-hidden="true" class="header-anchor">#</a> take</h3><p>take 是一个很简单的 operator，顾名思义就是取前几个元素后就结束，示例如下</p><pre class="language-javascript"><code><span class="token keyword">var</span> source <span class="token operator">=</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token function">interval</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> example <span class="token operator">=</span> source<span class="token punctuation">.</span><span class="token function">take</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

example<span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    next<span class="token punctuation">:</span> <span class="token punctuation">(</span>value<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    error<span class="token punctuation">:</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Error: '</span> <span class="token operator">+</span> err<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    complete<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'complete'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 0</span>
<span class="token comment">// 1</span>
<span class="token comment">// 2</span>
<span class="token comment">// complete</span>

</code></pre><p><a href="https://jsbin.com/jogesut/3/edit?js,console" target="_blank" rel="noopener noreferrer">JSBin</a> | <a href="https://jsfiddle.net/s6323859/ckyjuuva/1/" target="_blank" rel="noopener noreferrer">JSFiddle</a></p><p>这里可以看到我们的 <code>source</code> 原本是会发出无限个元素的，但这里我们用 <code>take(3)</code> 就会只取前 3 个元素，取完后就直接结束(complete)。</p><p>用 Marble diagram 表示如下</p><pre class="language-javascript"><code>source <span class="token punctuation">:</span> <span class="token operator">--</span><span class="token operator">--</span><span class="token operator">-</span><span class="token number">0</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">-</span><span class="token number">1</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">-</span><span class="token number">2</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">-</span><span class="token number">3</span><span class="token operator">--</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
                <span class="token function">take</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span>
example<span class="token punctuation">:</span> <span class="token operator">--</span><span class="token operator">--</span><span class="token operator">-</span><span class="token number">0</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">-</span><span class="token number">1</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">-</span><span class="token number">2</span><span class="token operator">|</span>

</code></pre><h3 id="first"><a href="#first" aria-hidden="true" class="header-anchor">#</a> first</h3><p>first 会取 observable 发送的第 1 个元素之后就直接结束，行为跟 take(1) 一致。</p><pre class="language-javascript"><code><span class="token keyword">var</span> source <span class="token operator">=</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token function">interval</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> example <span class="token operator">=</span> source<span class="token punctuation">.</span><span class="token function">first</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

example<span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    next<span class="token punctuation">:</span> <span class="token punctuation">(</span>value<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    error<span class="token punctuation">:</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Error: '</span> <span class="token operator">+</span> err<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    complete<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'complete'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token comment">// 0</span>
<span class="token comment">// complete</span>

</code></pre><p><a href="https://jsbin.com/jogesut/5/edit?js,console" target="_blank" rel="noopener noreferrer">JSBin</a> | <a href="https://jsfiddle.net/s6323859/ckyjuuva/3/" target="_blank" rel="noopener noreferrer">JSFiddle</a></p><p>用 Marble diagram 表示如下</p><pre class="language-javascript"><code>source <span class="token punctuation">:</span> <span class="token operator">--</span><span class="token operator">--</span><span class="token operator">-</span><span class="token number">0</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">-</span><span class="token number">1</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">-</span><span class="token number">2</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">-</span><span class="token number">3</span><span class="token operator">--</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
                <span class="token function">first</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
example<span class="token punctuation">:</span> <span class="token operator">--</span><span class="token operator">--</span><span class="token operator">-</span><span class="token number">0</span><span class="token operator">|</span>

</code></pre><h3 id="takeuntil"><a href="#takeuntil" aria-hidden="true" class="header-anchor">#</a> takeUntil</h3><p>在实务上 takeUntil 很常使用到，他可以在某件事情发生时，让一个 observable 发送 完成(complete)讯息，示例如下</p><pre class="language-javascript"><code><span class="token keyword">var</span> source <span class="token operator">=</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token function">interval</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> click <span class="token operator">=</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token function">fromEvent</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span>body<span class="token punctuation">,</span> <span class="token string">'click'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> example <span class="token operator">=</span> source<span class="token punctuation">.</span><span class="token function">takeUntil</span><span class="token punctuation">(</span>click<span class="token punctuation">)</span><span class="token punctuation">;</span>     

example<span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    next<span class="token punctuation">:</span> <span class="token punctuation">(</span>value<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    error<span class="token punctuation">:</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Error: '</span> <span class="token operator">+</span> err<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    complete<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'complete'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 0</span>
<span class="token comment">// 1</span>
<span class="token comment">// 2</span>
<span class="token comment">// 3</span>
<span class="token comment">// complete (点击body了</span>

</code></pre><p><a href="https://jsbin.com/jogesut/2/edit?js,console,output" target="_blank" rel="noopener noreferrer">JSBin</a> | <a href="https://jsfiddle.net/s6323859/ckyjuuva/" target="_blank" rel="noopener noreferrer">JSFiddle</a></p><p>这里我们一开始先用 <code>interval</code> 建立一个 observable，这个 observable 每隔 1 秒会发送一个从 0 开始递增的数值，接着我们用 <code>takeUntil</code>，传入另一个 observable。</p><p>当 <code>takeUntil</code> 传入的 observable 发送值时，原本的 observable 就会直接进入完成(complete)的状态，并且发送完成讯息。也就是说上面这段代码的行为，会先每 1 秒印出一个数字(从 0 递增)直到我们点击 body 为止，他才会发送 complete 讯息。</p><p>如果画成 Marble Diagram 则会像下面这样</p><pre class="language-javascript"><code>source <span class="token punctuation">:</span> <span class="token operator">--</span><span class="token operator">--</span><span class="token operator">-</span><span class="token number">0</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">-</span><span class="token number">1</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">-</span><span class="token number">2</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token number">3</span><span class="token operator">--</span>
click  <span class="token punctuation">:</span> <span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span>c<span class="token operator">--</span><span class="token operator">--</span>
                <span class="token function">takeUntil</span><span class="token punctuation">(</span>click<span class="token punctuation">)</span>
example<span class="token punctuation">:</span> <span class="token operator">--</span><span class="token operator">--</span><span class="token operator">-</span><span class="token number">0</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">-</span><span class="token number">1</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">-</span><span class="token number">2</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">|</span>

</code></pre><p>当 click 一发送元素的时候，observable 就会直接完成(complete)。</p><h3 id="concatall"><a href="#concatall" aria-hidden="true" class="header-anchor">#</a> concatAll</h3><p>有时我们的 Observable 发送的元素又是一个 observable，就像是二维数组，数组里面的元素是数组，这时我们就可以用 <code>concatAll</code> 把它摊平成一维数组，大家也可以直接把 concatAll 想成把所有元素 concat 起来。</p><pre class="language-javascript"><code><span class="token keyword">var</span> click <span class="token operator">=</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token function">fromEvent</span><span class="token punctuation">(</span>document<span class="token punctuation">.</span>body<span class="token punctuation">,</span> <span class="token string">'click'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> source <span class="token operator">=</span> click<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>e <span class="token operator">=&gt;</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token keyword">of</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">var</span> example <span class="token operator">=</span> source<span class="token punctuation">.</span><span class="token function">concatAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
example<span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    next<span class="token punctuation">:</span> <span class="token punctuation">(</span>value<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    error<span class="token punctuation">:</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Error: '</span> <span class="token operator">+</span> err<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    complete<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'complete'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

</code></pre><p><a href="https://jsbin.com/jogesut/6/edit?js,console,output" target="_blank" rel="noopener noreferrer">JSBin</a> | <a href="https://jsfiddle.net/s6323859/ckyjuuva/4/" target="_blank" rel="noopener noreferrer">JSFiddle</a></p><p>这个示例我们每点击一次 body 就会立刻发送 1,2,3，如果用 Marble diagram 表示则如下</p><pre class="language-javascript"><code>click  <span class="token punctuation">:</span> <span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span>c<span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span>c<span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span>

        <span class="token function">map</span><span class="token punctuation">(</span>e <span class="token operator">=&gt;</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token keyword">of</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span><span class="token number">2</span><span class="token punctuation">,</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">)</span>

source <span class="token punctuation">:</span> <span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span>o<span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span>o<span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span>
                \            \
                 <span class="token punctuation">(</span><span class="token number">123</span><span class="token punctuation">)</span><span class="token operator">|</span>       <span class="token punctuation">(</span><span class="token number">123</span><span class="token punctuation">)</span><span class="token operator">|</span>

                   <span class="token function">concatAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

example<span class="token punctuation">:</span> <span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token punctuation">(</span><span class="token number">123</span><span class="token punctuation">)</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token punctuation">(</span><span class="token number">123</span><span class="token punctuation">)</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span>

</code></pre><p>这里可以看到 <code>source</code> observable 内部每次发送的值也是 observable，这时我们用 concatAll 就可以把 source 摊平成 example。</p><p>这里需要注意的是 <code>concatAll</code> 会处理 source 先发出来的 observable，必须等到这个 observable 结束，才会再处理下一个 source 发出来的 observable，让我们用下面这个示例说明。</p><pre class="language-javascript"><code><span class="token keyword">var</span> obs1 <span class="token operator">=</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token function">interval</span><span class="token punctuation">(</span><span class="token number">1000</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">take</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> obs2 <span class="token operator">=</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token function">interval</span><span class="token punctuation">(</span><span class="token number">500</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">take</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> obs3 <span class="token operator">=</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token function">interval</span><span class="token punctuation">(</span><span class="token number">2000</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">take</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">var</span> source <span class="token operator">=</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token keyword">of</span><span class="token punctuation">(</span>obs1<span class="token punctuation">,</span> obs2<span class="token punctuation">,</span> obs3<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">var</span> example <span class="token operator">=</span> source<span class="token punctuation">.</span><span class="token function">concatAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

example<span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
    next<span class="token punctuation">:</span> <span class="token punctuation">(</span>value<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    error<span class="token punctuation">:</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Error: '</span> <span class="token operator">+</span> err<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>
    complete<span class="token punctuation">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'complete'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// 0</span>
<span class="token comment">// 1</span>
<span class="token comment">// 2</span>
<span class="token comment">// 3</span>
<span class="token comment">// 4</span>
<span class="token comment">// 0</span>
<span class="token comment">// 1</span>
<span class="token comment">// 0</span>
<span class="token comment">// complete</span>

</code></pre><p><a href="https://jsbin.com/jogesut/4/edit?js,console" target="_blank" rel="noopener noreferrer">JSBin</a> | <a href="https://jsfiddle.net/s6323859/ckyjuuva/2/" target="_blank" rel="noopener noreferrer">JSFiddle</a></p><p>这里可以看到 <code>source</code> 会发送 3 个 observable，但是 <code>concatAll</code> 后的行为永远都是先处理第一个 observable，<strong>等到当前处理的结束后才会再处理下一个</strong>。</p><p>用 Marble diagram 表示如下</p><pre class="language-javascript"><code>source <span class="token punctuation">:</span> <span class="token punctuation">(</span>o1                 o2      o3<span class="token punctuation">)</span><span class="token operator">|</span>
           \                  \       \
            <span class="token operator">--</span><span class="token number">0</span><span class="token operator">--</span><span class="token number">1</span><span class="token operator">--</span><span class="token number">2</span><span class="token operator">--</span><span class="token number">3</span><span class="token operator">--</span><span class="token number">4</span><span class="token operator">|</span>   <span class="token operator">-</span><span class="token number">0</span><span class="token operator">-</span><span class="token number">1</span><span class="token operator">|</span>   <span class="token operator">--</span><span class="token operator">--</span><span class="token number">0</span><span class="token operator">|</span>

                <span class="token function">concatAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span>        

example<span class="token punctuation">:</span> <span class="token operator">--</span><span class="token number">0</span><span class="token operator">--</span><span class="token number">1</span><span class="token operator">--</span><span class="token number">2</span><span class="token operator">--</span><span class="token number">3</span><span class="token operator">--</span><span class="token number">4</span><span class="token operator">-</span><span class="token number">0</span><span class="token operator">-</span><span class="token number">1</span><span class="token operator">--</span><span class="token operator">--</span><span class="token number">0</span><span class="token operator">|</span>

</code></pre><h2 id="简易拖拽"><a href="#简易拖拽" aria-hidden="true" class="header-anchor">#</a> 简易拖拽</h2><p>当学完前面几个 operator 后，我们就很轻松地做出拖拽的功能，先让我们来看一下需求</p><ol><li>首先画面上有一个元件(#drag)</li><li>当滑鼠在元件(#drag)上按下左键(mousedown)时，开始监听滑鼠移动(mousemove)的位置</li><li>当滑鼠左键放掉(mouseup)时，结束监听滑鼠移动</li><li>当滑鼠移动(mousemove)被监听时，跟着修改元件的样式属性</li></ol><p>第一步我已经完成了，大家可以直接到以下两个连结做练习</p><ul><li><a href="https://jsbin.com/yopawop/1/edit?js,output" target="_blank" rel="noopener noreferrer">JSBin</a></li><li><a href="https://jsfiddle.net/s6323859/dc0se480/" target="_blank" rel="noopener noreferrer">JSFiddle</a></li></ul><p>第二步我们要先取得各个 DOM 事件，元件(#drag) 跟 body。</p><pre class="language-javascript"><code><span class="token keyword">const</span> dragDOM <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'drag'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> body <span class="token operator">=</span> document<span class="token punctuation">.</span>body<span class="token punctuation">;</span>

</code></pre><p>要取得 body 的原因是因为滑鼠移动(mousemove)跟滑鼠左键放掉(mouseup)都应该是在整个 body 监听。</p><p>第三步我们写出各个会用到的监听事件，并用 <code>fromEvent</code> 来取得各个 observable。</p><ul><li>对 #drag 监听 mousedown</li><li>对 body 监听 mouseup</li><li>对 body 监听 mousemove</li></ul><pre class="language-javascript"><code><span class="token keyword">const</span> mouseDown <span class="token operator">=</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token function">fromEvent</span><span class="token punctuation">(</span>dragDOM<span class="token punctuation">,</span> <span class="token string">'mousedown'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> mouseUp <span class="token operator">=</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token function">fromEvent</span><span class="token punctuation">(</span>body<span class="token punctuation">,</span> <span class="token string">'mouseup'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> mouseMove <span class="token operator">=</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token function">fromEvent</span><span class="token punctuation">(</span>body<span class="token punctuation">,</span> <span class="token string">'mousemove'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

</code></pre><blockquote><p>记得还没 <code>subscribe</code> 之前都不会开始监听，一定会等到 subscribe 之后 observable 才会开始送值。</p></blockquote><p>第四步开始写逻辑</p><p><strong>当 mouseDown 时，转成 mouseMove 的事件</strong></p><pre class="language-javascript"><code><span class="token keyword">const</span> source <span class="token operator">=</span> mouseDown<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>event <span class="token operator">=&gt;</span> mouseMove<span class="token punctuation">)</span>

</code></pre><p><strong>mouseMove 要在 mouseUp 后结束</strong></p><p>加上 <code>takeUntil(mouseUp)</code></p><pre class="language-javascript"><code><span class="token keyword">const</span> source <span class="token operator">=</span> mouseDown
               <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>event <span class="token operator">=&gt;</span> mouseMove<span class="token punctuation">.</span><span class="token function">takeUntil</span><span class="token punctuation">(</span>mouseUp<span class="token punctuation">)</span><span class="token punctuation">)</span>

</code></pre><p>这时 source 大概长像这样</p><pre class="language-javascript"><code>source<span class="token punctuation">:</span> <span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">-</span>e<span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span><span class="token operator">--</span>e<span class="token operator">--</span><span class="token operator">--</span><span class="token operator">-</span>
                \              \
                  <span class="token operator">--</span>m<span class="token operator">-</span>m<span class="token operator">-</span>m<span class="token operator">-</span>m<span class="token operator">|</span>     <span class="token operator">-</span>m<span class="token operator">--</span>m<span class="token operator">-</span>m<span class="token operator">--</span>m<span class="token operator">-</span>m<span class="token operator">|</span>

</code></pre><blockquote><p>m 代表 mousemove event</p></blockquote><p>用 <code>concatAll()</code> 摊平 source 成一维。</p><pre class="language-javascript"><code><span class="token keyword">const</span> source <span class="token operator">=</span> mouseDown
               <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>event <span class="token operator">=&gt;</span> mouseMove<span class="token punctuation">.</span><span class="token function">takeUntil</span><span class="token punctuation">(</span>mouseUp<span class="token punctuation">)</span><span class="token punctuation">)</span>
               <span class="token punctuation">.</span><span class="token function">concatAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>                 

</code></pre><p>用 map 把 mousemove event 转成 x,y 的位置，并且订阅。</p><pre class="language-javascript"><code>source
<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>m <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token punctuation">{</span>
        x<span class="token punctuation">:</span> m<span class="token punctuation">.</span>clientX<span class="token punctuation">,</span>
        y<span class="token punctuation">:</span> m<span class="token punctuation">.</span>clientY
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span>pos <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  	dragDOM<span class="token punctuation">.</span>style<span class="token punctuation">.</span>left <span class="token operator">=</span> pos<span class="token punctuation">.</span>x <span class="token operator">+</span> <span class="token string">'px'</span><span class="token punctuation">;</span>
    dragDOM<span class="token punctuation">.</span>style<span class="token punctuation">.</span>top <span class="token operator">=</span> pos<span class="token punctuation">.</span>y <span class="token operator">+</span> <span class="token string">'px'</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>              

</code></pre><p>到这里我们就已经完成了简易的拖拽功能了!完整的代码如下</p><pre class="language-javascript"><code><span class="token keyword">const</span> dragDOM <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">'drag'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> body <span class="token operator">=</span> document<span class="token punctuation">.</span>body<span class="token punctuation">;</span>

<span class="token keyword">const</span> mouseDown <span class="token operator">=</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token function">fromEvent</span><span class="token punctuation">(</span>dragDOM<span class="token punctuation">,</span> <span class="token string">'mousedown'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> mouseUp <span class="token operator">=</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token function">fromEvent</span><span class="token punctuation">(</span>body<span class="token punctuation">,</span> <span class="token string">'mouseup'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> mouseMove <span class="token operator">=</span> Rx<span class="token punctuation">.</span>Observable<span class="token punctuation">.</span><span class="token function">fromEvent</span><span class="token punctuation">(</span>body<span class="token punctuation">,</span> <span class="token string">'mousemove'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

mouseDown
  <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>event <span class="token operator">=&gt;</span> mouseMove<span class="token punctuation">.</span><span class="token function">takeUntil</span><span class="token punctuation">(</span>mouseUp<span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">concatAll</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>event <span class="token operator">=&gt;</span> <span class="token punctuation">(</span><span class="token punctuation">{</span> x<span class="token punctuation">:</span> event<span class="token punctuation">.</span>clientX<span class="token punctuation">,</span> y<span class="token punctuation">:</span> event<span class="token punctuation">.</span>clientY <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
  <span class="token punctuation">.</span><span class="token function">subscribe</span><span class="token punctuation">(</span>pos <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  	dragDOM<span class="token punctuation">.</span>style<span class="token punctuation">.</span>left <span class="token operator">=</span> pos<span class="token punctuation">.</span>x <span class="token operator">+</span> <span class="token string">'px'</span><span class="token punctuation">;</span>
    dragDOM<span class="token punctuation">.</span>style<span class="token punctuation">.</span>top <span class="token operator">=</span> pos<span class="token punctuation">.</span>y <span class="token operator">+</span> <span class="token string">'px'</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span>

</code></pre><p>不知道读者有没有感受到，我们整个代码不到 15 行，而且只要能够看懂各个 operators，我们程式可读性是非常的高。</p><p>虽然这只是一个简单的拖拽实现，但已经展示出 RxJS 带来的威力，它让我们的代码更加的简洁，也更好的维护！</p><blockquote><p><a href="https://jsfiddle.net/s6323859/1ahzh7a7/2/" target="_blank" rel="noopener noreferrer">这里</a>有完整的成果可以参考。</p></blockquote><h2 id="今日小结"><a href="#今日小结" aria-hidden="true" class="header-anchor">#</a> 今日小结</h2><p>我们今天介绍了四个 operators 分别是 take, first, takeUntil, concatAll，并且完成了一个简易的拖拽功能，我们之后会把这个拖拽功能做得更完整，并且整合其他功能！</p><p>不知道读者今天有没有收获？如果有任何问题，欢迎在下方留言给我！
如果你喜欢这篇文章，请至标题旁帮我按个 星星＋like，谢谢。</p></div></div></div><div class="v-card__actions"><div class="flex xs12"><a href="/BLOG/tags/RXJS"><span tabindex="0" class="v-chip capitalize chip-tag v-chip--label v-chip--small"><span class="v-chip__content">RXJS</span></span></a></div></div></article></div><div class="flex text-xs-left xs6"><a href="/BLOG/posts/rxjs09.html" class="post-nav v-btn v-btn--flat v-btn--router"><div class="v-btn__content"><div class="grey--text"><i class="fa mr-1 fa-chevron-left"></i>Prev</div><div class="title mt-1 primary--text hidden-xs-only">09 Observable Operator - skip, takeLast, last, concat, startWith, merge</div></div></a></div><div class="flex text-xs-right xs6"><a href="/BLOG/posts/rxjs07.html" class="post-nav v-btn v-btn--flat v-btn--router"><div class="v-btn__content"><div class="grey--text">Next
          <i class="fa ml-1 fa-chevron-right"></i></div><div class="title mt-1 primary--text hidden-xs-only">07 Observable Operators &amp; Marble Diagrams</div></div></a></div><div class="flex mt-3 xs12"><div class="v-card" style="height:undefined;"><div class="v-card__title"><span class="headline">Comment</span></div></div></div></div></div><footer class="v-footer blog-footer darken-1 mt-3 theme--dark" style="height:auto;"><div class="primary--text text--lighten-4 text-xs-center py-3 v-card v-card--flat v-card--tile primary" style="height:undefined;"><div class="v-card__text pb-0">博客内容遵循 <a rel="license noopener noreferrer" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh" target="_blank">知识共享 署名 - 非商业性 - 相同方式共享 4.0 国际协议</a></div><div class="v-card__text pt-0 mt-1"><span>訾绍飞 © 2015 - 2018</span><span><!---->
        Power by
        <a href="https://vuepress.vuejs.org" target="_blank" rel="noopener noreferrer">VuePress</a> Theme
        <a href="https://github.com/ShaofeiZi/BLOG" target="_blank" rel="noopener noreferrer">indigo</a></span></div></div></footer></div></main><button type="button" class="v-btn v-btn--bottom v-btn--floating v-btn--fixed v-btn--right accent" style="display:none;"><div class="v-btn__content"><i class="fa fa-lg fa-chevron-up"></i></div></button></div></div></div>
    <script src="/BLOG/assets/js/26.407b2583.js" defer></script><script src="/BLOG/assets/js/app.1a725be8.js" defer></script>
  </body>
</html>
